// SFINAE详解
// SFINAE (Substitution Failure Is Not An Error) 是C++模板编程中的一个核心概念，它允许编译器在模板参数替换失败时，不将其视为错误，而是继续尝试其他可能的模板重载。
// 1. SFINAE基本原理
// SFINAE的基本原则是：
// 当模板参数替换导致无效代码时，该特化版本被丢弃
// 编译器会继续尝试其他可能的模板重载
// 只有当所有可能的重载都失败时，才会报错

// 2. SFINAE的应用场景
// 2.1 函数重载选择
// 只接受指针类型的版本
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type
process(T t)
{
    std::cout << "处理指针: " << *t << std::endl;
}

// 只接受非指针类型的版本
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, void>::type
process(T t)
{
    std::cout << "处理值: " << t << std::endl;
}

// 2.2 类模板特化
// 主模板
template <typename T, typename = void>
struct Container
{
    void add(const T &item)
    {
        std::cout << "添加单个项目" << std::endl;
    }
};

// 针对具有push_back方法的类型的特化
template <typename T>
struct Container<T, std::void_t<decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))>>
{
    void add(const T &container)
    {
        std::cout << "使用push_back添加到容器" << std::endl;
    }
};

// 3. SFINAE的实现技术
// 3.1 返回类型SFINAE
// 使用返回类型进行SFINAE
template <typename T>
auto get_value(T &container) -> decltype(container.front())
{
    return container.front();
}

// 后备版本
template <typename T>
auto get_value(T &value) -> T
{
    return value;
}

// 3.2 std::enable_if
// 使用std::enable_if控制函数重载
template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T>
square(T value)
{
    return value * value;
}

template <typename T>
std::enable_if_t<!std::is_arithmetic<T>::value, std::string>
square(T value)
{
    return "不能对非数值类型求平方";
}

// 3.3 约束与概念 (C++20)
// C++20中使用概念替代SFINAE
template <typename T>
    requires std::is_arithmetic_v<T>
T square_modern(T value)
{
    return value * value;
}

template <typename T>
    requires(!std::is_arithmetic_v<T>)
std::string square_modern(T value)
{
    return "不能对非数值类型求平方";
}

// 或使用简化语法
template <std::arithmetic T>
T square_concept(T value)
{
    return value * value;
}

// 4. SFINAE的高级应用
// 4.1 检测成员函数
// 检测类是否有特定的成员函数
template <typename T, typename = void>
struct has_serialize : std::false_type
{
};

template <typename T>
struct has_serialize<T, std::void_t<decltype(std::declval<T>().serialize())>>
    : std::true_type
{
};

// 使用
template <typename T>
void save(const T &obj)
{
    if constexpr (has_serialize<T>::value)
    {
        obj.serialize();
    }
    else
    {
        // 默认序列化逻辑
    }
}

// 4.2 完美转发与SFINAE
// 根据参数类型选择不同的实现
template <typename... Args>
auto create(Args &&...args) -> decltype(MyClass(std::forward<Args>(args)...), std::unique_ptr<MyClass>)
{
    return std::make_unique<MyClass>(std::forward<Args>(args)...);
}

template <typename... Args>
auto create(Args &&...args) -> decltype(MyOtherClass(std::forward<Args>(args)...), std::unique_ptr<MyOtherClass>)
{
    return std::make_unique<MyOtherClass>(std::forward<Args>(args)...);
}